package com.jsh.erp.controller;

import com.baomidou.mybatisplus.annotation.SqlParser;
import com.jsh.erp.constants.BusinessConstants;
import com.jsh.erp.datasource.entities.*;
import com.jsh.erp.datasource.mappers.*;
import com.jsh.erp.datasource.vo.StatementAccountVo;
import com.jsh.erp.service.statementaccount.StatementAccountService;
import com.jsh.erp.utils.BaseResponseInfo;
import com.jsh.erp.utils.ExcelUtils;
import com.jsh.erp.utils.Tools;
import io.swagger.annotations.*;
import jxl.Workbook;
import jxl.write.WritableWorkbook;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.URLEncoder;
import java.text.ParseException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 对账单信息
 * */


@RestController
@RequestMapping(value = "/statement")
@Api(tags = {"对账单查询"})
public class StatementAccountController {
    @Resource
    private DepotHeadMapper depotHeadMapper;

    @Resource
    private DepotItemMapper depotItemMapper;

    @Resource
    private SupplierMapper supplierMapper;

    @Resource
    private MaterialMapper materialMapper;

    @Resource
    private MaterialExtendMapper materialExtendMapper;
    @Resource
    private StatementAccountService statementAccountService;


    @PostMapping(value = "/updateStatement")
    @ApiOperation(value = "手动更新对账单")
    @ApiResponses(value = {
            @ApiResponse(code = 200, message = "Successful", response = StatementAccountVo.class),
            // 修改这里的message来改变返回参数的说明
            @ApiResponse(code = 404, message = "Not Found. The resource you were trying to get could not be found.")

    })

    public BaseResponseInfo updateStatement() {

        BaseResponseInfo res = new BaseResponseInfo();
        Map<String, Object> map = new HashMap<>();
        //以订单子表为主表计算
        DepotHeadExample example = new DepotHeadExample();
        example.createCriteria().andDeleteFlagNotEqualTo(BusinessConstants.DELETE_FLAG_DELETED)
                .andTypeEqualTo("其它").andSubTypeIn(Arrays.asList("采购订单", "销售订单")).andStatusNotIn(Arrays.asList("0", "9"));
        //1. 获取所有采购订单或销售订单
        List<DepotHead> list= depotHeadMapper.selectByExample(example);
        if(list.isEmpty()){
            res.code = 500;
            res.data = "获取数据失败";
            return res;
        }
        List<Long> ids = list.stream().map(DepotHead::getId).collect(Collectors.toList());
        List<Long> supplierIds = list.stream().map(DepotHead::getOrganId).collect(Collectors.toList());
        Map<Long, List<DepotHead>> headMap = list.stream().collect(Collectors.groupingBy(DepotHead::getId));
        //2. 查询 采购订单或销售订单子表
        DepotItemExample itemExample = new DepotItemExample();
        itemExample.createCriteria().andDeleteFlagNotEqualTo(BusinessConstants.DELETE_FLAG_DELETED).andHeaderIdIn(ids);
        List<DepotItem> depotItems = depotItemMapper.selectByExample(itemExample);
        Map<Long, List<DepotItem>> itemMap = depotItems.stream().collect(Collectors.groupingBy(DepotItem::getHeaderId));
        List<Long> materialIds = depotItems.stream().map(DepotItem::getMaterialId).collect(Collectors.toList());
        List<Long> materialExtendIds = depotItems.stream().map(DepotItem::getMaterialExtendId).collect(Collectors.toList());
        List<Long> linkIds = depotItems.stream().map(DepotItem::getId).collect(Collectors.toList());

        // 3. 查询供应商/客户信息
        SupplierExample supplierExample = new SupplierExample();
        supplierExample.createCriteria().andDeleteFlagNotEqualTo(BusinessConstants.DELETE_FLAG_DELETED).andIdIn(supplierIds);
        Map<Long, List<Supplier>> supplierMap = supplierMapper.selectByExample(supplierExample).stream().collect(Collectors.groupingBy(Supplier::getId));

        //4.查询产品信息
        MaterialExample materialExample = new MaterialExample();
        materialExample.createCriteria().andDeleteFlagNotEqualTo(BusinessConstants.DELETE_FLAG_DELETED).andIdIn(materialIds);
        List<Material> materials = materialMapper.selectByExample(materialExample);
        Map<Long, List<Material>> materialMap = materials.stream().collect(Collectors.groupingBy(Material::getId));

        //5. 查询产品扩展信息
        MaterialExtendExample materialExtendExample = new MaterialExtendExample();
        materialExtendExample.createCriteria().andDeleteFlagNotEqualTo(BusinessConstants.DELETE_FLAG_DELETED)
                .andIdIn(materialExtendIds);
        List<MaterialExtend> materialExtends = materialExtendMapper.selectByExample(materialExtendExample);
        Map<Long, List<MaterialExtend>> materialExtendMap = materialExtends.stream().collect(Collectors.groupingBy(MaterialExtend::getId));
        //7.查询出入库子表信息
        List<DepotItem> inAndOutItems;
        itemExample.clear();
        itemExample.createCriteria().andDeleteFlagNotEqualTo(BusinessConstants.DELETE_FLAG_DELETED).andLinkIdIn(linkIds);
        inAndOutItems = depotItemMapper.selectByExample(itemExample);
        List<Long> inOutItemIds = inAndOutItems.stream().map(DepotItem::getId).collect(Collectors.toList());
        Map<Long, List<DepotItem>> inAndOutItemMap = inAndOutItems.stream().collect(Collectors.groupingBy(DepotItem::getLinkId));

        //6. 查询退货单  查询退货出入库子表信息 与出入库子表关联，可能为空，需要判空
        List<DepotItem> backItems = new ArrayList<>();
        if (!inOutItemIds.isEmpty()){
            itemExample.clear();
            itemExample.createCriteria().andDeleteFlagNotEqualTo(BusinessConstants.DELETE_FLAG_DELETED).andLinkIdIn(inOutItemIds);
            backItems = depotItemMapper.selectByExample(itemExample);
        }
        Map<Long, List<DepotItem>> backItemsMap = backItems.stream().collect(Collectors.groupingBy(DepotItem::getLinkId));

        List<StatementAccountVo> vos = depotItems.stream().map(x -> {
            //采购或销售主表
            DepotHead head = headMap.get(x.getHeaderId()).get(0);
            //供应商 or 客户信息
            Supplier supplier = supplierMap.get(head.getOrganId()).get(0);
            //产品主表
            Material material = materialMap.get(x.getMaterialId()).get(0);
            //产品扩展表
            MaterialExtend materialExtend = materialExtendMap.get(x.getMaterialExtendId()).get(0);
            //出入库子表
            List<DepotItem> items = inAndOutItemMap.getOrDefault(x.getId(),new ArrayList<>());

            StatementAccountVo vo = new StatementAccountVo();
            vo.setId(x.getId());//以子订单ID为唯一主键
            vo.setOperTime(head.getOperTime());
            vo.setTenantId(head.getTenantId());
            vo.setStatisticalType("系统计算");
            vo.setStatementType(head.getType().equals("出库") && head.getSubType().equals("销售") ? "销售对账单" : "采购对账单");
            vo.setSupplierNumber(supplier.getNumber());
            vo.setSupplierName(supplier.getSupplier());
            vo.setDepotNumber(head.getNumber());
            vo.setBarCode(materialExtend.getBarCode());
            vo.setMaterials(material.getName() + " " + material.getModel() + " " + material.getStandard() + " " + material.getVersion() + " " + materialExtend.getSku());
            vo.setMaterialUnit(material.getUnit());
            vo.setOrderPeople(head.getSalesMan());
            vo.setUnitPrice(x.getUnitPrice());
            //订单数量
            BigDecimal operNumber = x.getOperNumber();//订单数量
            BigDecimal allPrice = x.getAllPrice();//订单总价，不含税
            BigDecimal taxLastMoney = x.getTaxLastMoney();//订单总价，含税
            vo.setInvoiceNum(operNumber);

            //入库数量= 已入库-已退货  出库数量=已出库-已退货
            //没有入库时，入库数量为0,仍要开票数量取订单数量
            if (items.isEmpty()) {
                vo.setMaterialCount(new BigDecimal(0));
                vo.setInvoiceNum(operNumber);
                vo.setNeedInvoice(allPrice);
                vo.setNeedInvoiceTax(taxLastMoney);
            } else {
                final BigDecimal[] materialCount = {new BigDecimal(0)};
                BigDecimal invoiceNum;
                final BigDecimal[] needInvoice = {new BigDecimal(0)};
                final BigDecimal[] needInvoiceTax = {new BigDecimal(0)};
                //遍历出入库子表查询
                items.forEach(i -> {
                    //退货单子表
                    List<DepotItem> backs = backItemsMap.getOrDefault(i.getId(),new ArrayList<>());
                    //当没有退货单时，累加计算出入库单
                    if (!backs.isEmpty()) {
                        backs.forEach(b -> {
                            //累加已入库数
                            materialCount[0] = materialCount[0].multiply(b.getOperNumber());
                            needInvoice[0] = needInvoice[0].multiply(b.getAllPrice());
                            needInvoiceTax[0] = needInvoiceTax[0].multiply(b.getTaxLastMoney());
                        });
                    }
                    //累加已入库数
                    materialCount[0] = materialCount[0].add(i.getOperNumber());
                    needInvoice[0] = needInvoice[0].add(i.getAllPrice());
                    needInvoiceTax[0] = needInvoiceTax[0].add(i.getTaxLastMoney());
                });
                // 仍要开票数 = 订单数量 - 已入库数量
                invoiceNum = operNumber.multiply(materialCount[0]);
                vo.setMaterialCount(materialCount[0]);
                vo.setInvoiceNum(invoiceNum);
                vo.setNeedInvoice(needInvoice[0]);
                vo.setNeedInvoiceTax(needInvoiceTax[0]);
            }
            return vo;
        }).collect(Collectors.toList());
        statementAccountService.batchInsertStatementAccountVo(vos);
        res.code = 200;
        res.data = "更新对账单信息成功";

        return res;
    }
    @GetMapping(value = "/exportExcel")
    public void exportExcel(
                            @RequestParam(value = "statementType", required = false)String statementType,
                            @RequestParam(value = "supplierNumber", required = false)String supplierNumber,
                            @RequestParam(value = "supplierName", required = false)String supplierName,
                            @RequestParam(value = "beginTime", required = false)String beginTime,
                            @RequestParam(value = "endTime", required = false)String endTime,
                            HttpServletRequest request, HttpServletResponse response) {
        try {
            List<StatementAccountVo> dataList = statementAccountService.findByAll(statementType,supplierNumber,supplierName, beginTime, endTime);
            File file = statementAccountService.exportExcel(dataList);
            ExcelUtils.downloadExcel(file, file.getName(), response);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    @PostMapping(value = "/importPurchaseAccount")
    @ApiOperation(value = "导入对账单")
    public BaseResponseInfo importPurchaseAccount(MultipartFile file,
                                         HttpServletRequest request, HttpServletResponse response) throws Exception{
        BaseResponseInfo res = new BaseResponseInfo();
        try {
            statementAccountService.importExcel("采购对账单",file, request);
            res.code = 200;
            res.data = "导入成功";
        } catch(Exception e){
            e.printStackTrace();
            res.code = 500;
            res.data = "导入失败";
        }
        return res;
    }
    @PostMapping(value = "/importSaleAccount")
    @ApiOperation(value = "导入对账单")
    public BaseResponseInfo importSaleAccount(MultipartFile file,
                                         HttpServletRequest request, HttpServletResponse response) throws Exception{
        BaseResponseInfo res = new BaseResponseInfo();
        try {
            statementAccountService.importExcel("销售对账单",file, request);
            res.code = 200;
            res.data = "导入成功";
        } catch(Exception e){
            e.printStackTrace();
            res.code = 500;
            res.data = "导入失败";
        }
        return res;
    }
}
